package utils;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.*;


public class TokenManager {
    private static ScheduledExecutorService scheduledExecutorService;

    private static Map<String, String> tokenMap = new LinkedHashMap<String, String>();

    private static Map<String, ScheduledFuture<?>> futureMap = new HashMap<String, ScheduledFuture<?>>();

    private  int poolSize = 1;

    private  boolean daemon = Boolean.TRUE;

    private static TokenManager instance = new TokenManager();

    private TokenManager() {
    }

    public static TokenManager getInstance() {
        return instance;
    }

    /**
     * 初始化 scheduledExecutorService
     */
    private void initScheduledExecutorService() {
        scheduledExecutorService = Executors.newScheduledThreadPool(poolSize, threadName -> {
            Thread thread = Executors.defaultThreadFactory().newThread(threadName);
            //设置守护线程
            thread.setDaemon(daemon);
            return thread;
        });
    }

    /**
     * 设置线程池
     *
     * @param poolSize poolSize
     */
    public void setPoolSize(int poolSize) {
        this.poolSize = poolSize;
    }

    /**
     * 设置线程方式
     *
     * @param daemon daemon
     */
    public void setDaemon(boolean daemon) {
        this.daemon = daemon;
    }

    /**
     * 初始化token 刷新，每1天刷新一次。
     */
    public void init(final String apiKey, Callable<String> callable) {
        init(apiKey, 0, 1 * 24 * 60 * 60, callable);
    }

    /**
     * 初始化token 刷新，每1天刷新一次。
     *
     * @param initialDelay 首次执行延迟（秒）
     * @param delay        执行间隔（秒）
     */
    public void init(final String apiKey, int initialDelay, int delay, Callable<String> callable) {
        if (scheduledExecutorService == null) {
            initScheduledExecutorService();
        }

        if (futureMap.containsKey(apiKey)) {
            futureMap.get(apiKey).cancel(true);
        }
        //立即执行一次
        if (initialDelay == 0) {
            doRun(apiKey, callable);
        }
        ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> doRun(apiKey, callable), initialDelay == 0 ? delay : initialDelay, delay, TimeUnit.SECONDS);
        futureMap.put(apiKey, scheduledFuture);
    }

    private void doRun(final String apiKey, Callable<String> callable) {
        try {
            String access_token = callable.call();
            tokenMap.put(apiKey, access_token);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 取消 token 刷新
     */
    public void destroyed() {
        scheduledExecutorService.shutdownNow();
    }

    /**
     * 获取
     *
     * @return token
     */
    public String getToken(String apiKey) {
        return tokenMap.get(apiKey);
    }

}